/**
 * @export
 * @class Landuse
 * @classdesc 绿地类
 * @property {Object} 地图容器 - SchoolLab实例
 * @property {String} name - 名称
 * @property {String} map - 贴图
 * @property {Boolean} useMap - 是否使用贴图
 * @property {String} color - 颜色
 * @property {Number} opacity - 透明度
 * @property {Number} radius - 半径
 * @property {Number} renderOrder - 层叠顺序
 * @property {Array} path - 边缘轮廓
 * @example
 * var landuse = new Landuse(viewer, {
 *   radius: 4,
 *   color: '#ff0000',
 *   opacity: 0.5,
 *   renderOrder: 20,
 *   name: 'landuse',
 *   useMap: true,
 *   map: '../image/xx.png',
 *   path: []
 * })
 */
import { extend, isArray, lngLatToWorld, transformCoordinate } from './util'
import Feature from './Feature'
export default class Landuse {
  constructor(viewer, options) {
    const opts = extend({
      name: "landuse",
      color: "#ffffff",
      map: null,
      opacity: 1,
      useMap: false,
      renderOrder: 1
    }, options)


    /** @member {SchoolLab} - 地图容器 */
    this.viewer = viewer
    
    /** @member {String} - 名称 */
    this.name = opts.name
    
    /** @member {Color} - 颜色 */
    this.color = opts.color
    
    /** @member {Number} - 透明度 */
    this.opacity = opts.opacity
    
    /** @member {Boolean} - 是否使用贴图 */
    this.useMap = opts.useMap
    
    /** @member {String} - 贴图地址 */
    this.map = opts.map
    
    /** @member {Array} - 轮廓点集 */
    this.path = opts.path
    
    /** @member {Number} - 层叠顺序 */
    this.renderOrder = opts.renderOrder
    
    /** @member {THREE.Mesh} - mesh对象 */
    this.entity = null

    Feature.apply(this)

    this._init()
  }

  _init() {
    let geometry = this._initGeometry()
    let material = this._initMaterial()
    
    const mesh = new THREE.Mesh(geometry, material)
    mesh.name = this.name
    mesh.renderOrder = this.renderOrder
    
    this.entity = mesh
    this.viewer.world.add(mesh)
  }

  // 初始化几何体
  _initGeometry() {
    const formatPath = this._formatPolygonPath(this.path)
    const _path = this._getGeographicPolygonFormat(this.viewer.gisCenter, formatPath)
    const geometry = new THREE.Geometry()

    for (let i = 0; i < _path.length; i++) {
      if (isArray(_path[i][0])) {
        let shape = null
        for (let j = 0; j < _path[i].length; j++) {
          if (j === 0) {
            shape = new THREE.Shape(_path[i][j])
          } else {
            shape.holes.push(new THREE.Path(_path[i][j]))
          }
        }
        const unitGeo = new THREE.ShapeGeometry(shape)
        let unitMesh = new THREE.Mesh(unitGeo, new THREE.MeshBasicMaterial())
        unitMesh.updateMatrix()
        geometry.merge(unitMesh.geometry, unitMesh.matrix)
        unitMesh.geometry.dispose()
        unitMesh.material.dispose()
        unitMesh = null
      } else {
        const unitGeo = new THREE.ShapeGeometry(new THREE.Shape(_path[i]))
        let unitMesh = new THREE.Mesh(unitGeo, new THREE.MeshBasicMaterial())
        unitMesh.updateMatrix()
        geometry.merge(unitMesh.geometry, unitMesh.matrix)
        unitMesh.geometry.dispose()
        unitMesh.material.dispose()
        unitMesh = null
      }
    }
    geometry.computeBoundingBox()
    const max = geometry.boundingBox.max
    const min = geometry.boundingBox.min
    const offset = new THREE.Vector2(0 - min.x, 0 - min.y)
    const range = new THREE.Vector2(max.x - min.x, max.y - min.y)
    const faces = geometry.faces
    geometry.faceVertexUvs[0] = []
    for (let i = 0; i < faces.length; i++) {
      const v1 = geometry.vertices[faces[i].a]
      const v2 = geometry.vertices[faces[i].b]
      const v3 = geometry.vertices[faces[i].c]
      geometry.faceVertexUvs[0].push([
        new THREE.Vector2((v1.x + offset.x) / range.x, (v1.y + offset.y) / range.y),
        new THREE.Vector2((v2.x + offset.x) / range.x, (v2.y + offset.y) / range.y),
        new THREE.Vector2((v3.x + offset.x) / range.x, (v3.y + offset.y) / range.y)
      ])
    }
    geometry.uvsNeedUpdate = true

    return new THREE.BufferGeometry().fromGeometry(geometry)
  }

  // 初始化材质
  _initMaterial() {
    const uniforms = {
      color: { type: 'c', value: new THREE.Color(this.color) },
      opacity: { type: 'f', value: this.opacity },
      map: { type: 't', value: null },
      useMap: { type: 'b', value: this.useMap }
    }

    let vs = this._initVS()
    let fs = this._initFS()
    const material = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vs,
      fragmentShader: fs,
      transparent: true,
      depthWrite: false,
      depthTest: true,
      side: THREE.DoubleSide
    })

    let loader = new THREE.TextureLoader()
    if (this.useMap) {
      const map = loader.load(this.map)
      map.wrapS = map.wrapT = THREE.RepeatWrapping
      map.generateMipmaps = false
      map.magFilter = THREE.LinearFilter
      map.minFilter = THREE.LinearFilter
      material.uniforms.map.value = map
      material.needsUpdate = true
    }

    return material
  }

  // 初始化vertexShader
  _initVS() {
    let vs = `
      precision lowp float;
      precision lowp int;
      #include <fog_pars_vertex>
      varying vec2 vUv;
      void main() {
        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        #include <fog_vertex>
      }
    `
    return vs
  }

  // 初始化fragmentShader
  _initFS() {
    let fs = `
      uniform sampler2D map;
      uniform bool useMap;
      uniform vec3 color;
      uniform float opacity;
      varying vec2 vUv;
      void main() {
        if (useMap) {
          gl_FragColor = texture2D(map, vUv);
          gl_FragColor.a *= opacity;
        } else {
          gl_FragColor = vec4(color, opacity);
        }
      }
    `
    return fs
  }

  // 格式化轮廓路径数据
  _formatPolygonPath(geojsonArr) {
    const formatPath = []
    for (let i = 0; i < geojsonArr.length; i++) {
      const type = geojsonArr[i].geometry && geojsonArr[i].geometry.type
      if (type === 'MultiPolygon') {
        const coordinates = geojsonArr[i].geometry.coordinates
        let j = 0
        while (j < coordinates.length) {
          const coordinate = coordinates[j]
  
          if (coordinate.length === 1) {
            const _coordinate = coordinate[0]
            const path = []
            for (let k = 0, len = _coordinate.length; k < len; k++) {
              path.push(new THREE.Vector3(_coordinate[k][0], _coordinate[k][1], 0))
            }
            formatPath.push(path)
          } else {
            const path = []
            for (let k = 0; k < coordinate.length; k++) {
              const _coordinate = coordinate[k]
              const _path = []
              for (let l = 0, len = _coordinate.length; l < len; l++) {
                _path.push(new THREE.Vector3(_coordinate[l][0], _coordinate[l][1], 0))
              }
              path.push(_path)
            }
            formatPath.push(path)
          }
          j++
        }
      } else if (type === 'Polygon') {
        const coordinates = geojsonArr[i].geometry.coordinates
        if (coordinates.length === 1) {
          const coordinate = coordinates[0]
          const path = []
          for (let j = 0, len = coordinate.length; j < len; j++) {
            path.push(new THREE.Vector3(coordinate[j][0], coordinate[j][1], 0))
          }
          formatPath.push(path)
        } else {
          const path = []
          for (let j = 0; j < coordinates.length; j++) {
            const coordinate = coordinates[j]
            const _path = []
            for (let k = 0, len = coordinate.length; k < len; k++) {
              _path.push(new THREE.Vector3(coordinate[k][0], coordinate[k][1], 0))
            }
            path.push(_path)
          }
          formatPath.push(path)
        }
      } else if (!type) {
        const coordinates = geojsonArr[i]
        const path = []
        for (let j = 0; j < coordinates.length; j++) {
          const coordinate = coordinates[j]
          const _path = []
          for (let k = 0, len = coordinate.length; k < len; k++) {
            _path.push(coordinate[k])
          }
          path.push(_path)
        }
        formatPath.push(path)
      }
    }
    return formatPath
  }

  // gis坐标转换
  _getGeographicPolygonFormat(gisCenterPos, path) {
    const _path = []
  
    for (let i = 0; i < path.length; i++) {
      const unitPath = path[i]
      if (isArray(unitPath[0])) {
        const formatPath = []
        for (let j = 0; j < unitPath.length; j++) {
          let _formatPath = []
          _formatPath = unitPath[j].map((vec) => {
            const pos = lngLatToWorld([vec.x, vec.y])
            const format = transformCoordinate(gisCenterPos, pos)
            return new THREE.Vector3(format.x, format.y, vec.z)
          })
          formatPath.push(_formatPath)
        }
        _path.push(formatPath)
      } else {
        let formatPath = []
        formatPath = unitPath.map((vec) => {
          const pos = lngLatToWorld([vec.x, vec.y])
          const format = transformCoordinate(gisCenterPos, pos)
          return new THREE.Vector3(format.x, format.y, vec.z)
        })
        _path.push(formatPath)
      }
    }

    return _path
  }

  // 动画时间系数更新
  _update() {
    this.entity.material.uniforms.time.value += 0.1
  }

  // 销毁动画
  destroy() {
    this._disposeHierarchy(this.entity, this._dispose)
    this.viewer.world.remove(this.entity)
    this.entity = null
  }
}
